﻿using System;
using System.Collections.Generic;

using FineCollection.Intf;


using math = System.Math;
using arrays = System.Array;


namespace FineCollection.Const
{

    /// <summary>
    /// Constant sorted map.
    /// </summary>
    /// <typeparam name="K">type of an entry key.</typeparam>
    /// <typeparam name="V">type of an entry value.</typeparam>
    public class ConstSortMap<K,V> : ConstSortSet<ComparableMapEntry<K,V>>, RMap<K,V>
        where K: IComparable<K>
    {
        internal static readonly IComparer<K> comparer =
            Comparer<K>.Default;


        internal ConstSortMap(int firstIndex, ComparableMapEntry<K,V>[] entries) 
            : base(firstIndex, entries, entries.Length, true, true, false)
        {}


        internal ConstSortMap(int firstIndex, ComparableMapEntry<K,V>[] entries, int count, bool takeOwnership)
            : base(firstIndex, entries, count, true, true, takeOwnership)
        {}




        public V Find(K key, V notFound)
        {
            int zIndex = ZeroBasedIndexOf(key);
            return (zIndex >= 0) ? arr[zIndex].Value : notFound;
        }


        public V this[K key]
        {
            get { return Find(key, default(V)); }
        }


        public bool ContainsKey(K key)
        {
            int index = IndexOf(key);
            return index > 0;
        }


        /// <summary>
        /// Looks for the map entry with the specified key, and return its index.
        /// </summary>
        /// <param name="key">key for looking for.</param>
        /// <returns>index of the found entry (started with <see cref="ConstArray{T}.FirstIndex"/>),
        ///          or <see cref="int.MinValue"/> if not found.</returns>
        public int IndexOf(K key)
        {
            int zIndex = ZeroBasedIndexOf(key);
            return zIndex >= 0 ? firstIndex + zIndex : int.MinValue;
        }


        private int ZeroBasedIndexOf(K key) 
        {
            if (count == 0)
                return int.MinValue;

            var fakeEntry = new MapEntry<K, V>(key, default(V));
            return Array.BinarySearch(arr, 0, count, fakeEntry, EntriesComparer);
        }


        public MapEntry<K,V>[] ListAllEntries()
        {
            var result = new MapEntry<K,V>[count];
            arrays.Copy(arr, result, count);
            return result;
        }



        #region MAP ENTRIES COMPARATOR

        internal class MapEntriesComparer : IComparer<MapEntry<K, V>>
        {
            public int Compare(MapEntry<K,V> x, MapEntry<K,V> y)
            {
                if (x == y) return 0;
                if (x == null) return -1;
                if (y == null) return +1;
                return comparer.Compare(x.Key, y.Key);
            }
        }

        internal static readonly MapEntriesComparer EntriesComparer = new MapEntriesComparer();

        #endregion
    }


}